import { Request, Response, NextFunction } from 'express';
import { AppError } from '../types/index';
import logger from '@utils/logger';
import config from '@config/index';

/**
 * 全局错误处理中间件
 */
const errorHandler = (
  error: Error | AppError,
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  let statusCode = 500;
  let message = 'Internal Server Error';
  let isOperational = false;

  // 检查是否是自定义应用错误
  if (error instanceof AppError) {
    statusCode = error.statusCode;
    message = error.message;
    isOperational = error.isOperational;
  }
  // MongoDB 错误处理
  else if (error.name === 'ValidationError') {
    statusCode = 400;
    message = 'Validation Error';
    const validationErrors = Object.values((error as any).errors).map(
      (err: any) => err.message
    );
    message = validationErrors.join(', ');
  }
  // MongoDB 重复键错误
  else if ((error as any).code === 11000) {
    statusCode = 409;
    message = 'Duplicate field value';
    const field = Object.keys((error as any).keyValue)[0];
    message = `${field} already exists`;
  }
  // JWT 错误
  else if (error.name === 'JsonWebTokenError') {
    statusCode = 401;
    message = 'Invalid token';
  }
  else if (error.name === 'TokenExpiredError') {
    statusCode = 401;
    message = 'Token expired';
  }
  // Mongoose Cast 错误
  else if (error.name === 'CastError') {
    statusCode = 400;
    message = 'Invalid ID format';
  }

  // 记录错误日志
  const logLevel = statusCode >= 500 ? 'error' : 'warn';
  logger[logLevel](`${req.method} ${req.path} - ${statusCode} - ${message}`, error, {
    statusCode,
    userAgent: req.get('User-Agent'),
    ip: req.ip,
    userId: (req as any).user?.id,
    stack: error.stack,
  });

  // 构建错误响应
  const errorResponse: any = {
    success: false,
    error: message,
    statusCode,
  };

  // 开发环境下包含更多错误信息
  if (config.isDevelopment) {
    errorResponse.stack = error.stack;
    errorResponse.isOperational = isOperational;
  }

  // 添加请求ID (如果有)
  if ((req as any).requestId) {
    errorResponse.requestId = (req as any).requestId;
  }

  res.status(statusCode).json(errorResponse);
};

export default errorHandler;